package br.ufrn.btest.tests.unit;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.junit.Test;

import br.ufrn.btest.criterias.Pairwise;
import br.ufrn.btest.exceptions.InvalidInputDataException;

public class PairwiseCriteriaTest {

	@Test(expected = InvalidInputDataException.class)
	public void shouldRaiseExceptionForAnEmptyInputList() throws InvalidInputDataException {
		List<List<String>> inputs = new ArrayList<List<String>>();
		Pairwise pairwise = new Pairwise(inputs);
		pairwise.getCombinations();
	}

	@Test(expected = InvalidInputDataException.class)
	public void shoudRaiseExceptionForInputListWithOneParameter() throws InvalidInputDataException {
		List<List<String>> inputs = new ArrayList<List<String>>();
		
		List<String> paramValues = new ArrayList<String>();
		paramValues.add("A1");
		paramValues.add("A2");

		inputs.add(paramValues);
		
		Pairwise pairwise = new Pairwise(inputs);
		pairwise.getCombinations();
	}

	@Test
	public void shouldGenerateCombinationsForTwoParametersWithOneValues() {
		List<List<String>> inputs = new ArrayList<List<String>>();
		
		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);

		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("A1 & B1");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	
	@Test
	public void shouldGenerateCombinationsForThreeParametersWithOneValues() {
		List<List<String>> inputs = new ArrayList<List<String>>();
		
		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("C1");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		
		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("A1 & B1 & C1");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	
	
	@Test
	public void shouldGenerateCombinationsForThreeParametersWithTwoValues() {
		List<List<String>> inputs = new ArrayList<List<String>>();
		
		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		paramAValues.add("A2");
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		paramBValues.add("B2");
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("C1");
		paramCValues.add("C2");
		
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		
		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("A1 & B1 & C1");
		expectedCombinations.add("A1 & B2 & C2");
		expectedCombinations.add("A2 & B1 & C2");
		expectedCombinations.add("A2 & B2 & C1");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}

	@Test
	public void shouldGenerateCombinationsForFourParametersWithTwoValues() {
		List<List<String>> inputs = new ArrayList<List<String>>();
		
		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		paramAValues.add("A2");
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		paramBValues.add("B2");
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("C1");
		paramCValues.add("C2");
		List<String> paramDValues = new ArrayList<String>();
		paramDValues.add("D1");
		paramDValues.add("D2");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		inputs.add(paramDValues);
		
		Set<String> expectedCombinations = new HashSet<String>();

		expectedCombinations.add("A1 & B2 & C2 & D1");
		expectedCombinations.add("A2 & B1 & C1 & D1");
		expectedCombinations.add("A2 & B1 & C2 & D2");
		expectedCombinations.add("A2 & B2 & C1 & D2");
		expectedCombinations.add("A1 & B1 & C1 & D1");
		expectedCombinations.add("A1 & B1 & C1 & D2");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	
	@Test
	public void shouldGenerateCombinationsForThreeParametersWithUnequalValueLengths(){
		List<List<String>> inputs = new ArrayList<List<String>>();

		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("C1");
		paramCValues.add("C2");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		
		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("A1 & B1 & C1");
		expectedCombinations.add("A1 & B1 & C2");
		
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	
	
	@Test
	public void shouldGenerateCombinationsForThreeParametersWithUnequalValueLengths2(){
		List<List<String>> inputs = new ArrayList<List<String>>();

		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("C1");
		paramCValues.add("C2");
		paramCValues.add("C3");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		
		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("A1 & B1 & C1");
		expectedCombinations.add("A1 & B1 & C2");
		expectedCombinations.add("A1 & B1 & C3");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	

	@Test
	public void shouldGenerateCombinationsForThreeParametersWithUnequalValueLengths3(){
		List<List<String>> inputs = new ArrayList<List<String>>();

		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		paramBValues.add("B2");
		
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("C1");
		paramCValues.add("C2");
		paramCValues.add("C3");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		
		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("A1 & B1 & C1");
		expectedCombinations.add("A1 & B2 & C2");
		expectedCombinations.add("A1 & B2 & C1");
		expectedCombinations.add("A1 & B1 & C2");
		expectedCombinations.add("A1 & B1 & C3");
		expectedCombinations.add("A1 & B2 & C3");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	
	
	@Test
	public void shouldGenerateCombinationsForThreeParametersWithUnequalValueLengths4(){
		List<List<String>> inputs = new ArrayList<List<String>>();

		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		paramAValues.add("A2");
		
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("C1");
		paramCValues.add("C2");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		
		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("A1 & B1 & C1");
		expectedCombinations.add("A2 & B1 & C2");
		expectedCombinations.add("A2 & B1 & C1");
		expectedCombinations.add("A1 & B1 & C2");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	
	
	@Test
	public void shouldGenerateCombinationsForThreeParametersWithUnequalValueLengths5(){
		List<List<String>> inputs = new ArrayList<List<String>>();

		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		paramAValues.add("A2");
		
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("C1");
		paramCValues.add("C2");
		
		List<String> paramDValues = new ArrayList<String>();
		paramDValues.add("D1");
		paramDValues.add("D2");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		inputs.add(paramDValues);
		
		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("A2 & B1 & C2 & D1");
		expectedCombinations.add("A1 & B1 & C2 & D2");
		expectedCombinations.add("A2 & B1 & C1 & D2");
		expectedCombinations.add("A1 & B1 & C1 & D1");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	

	@Test
	public void shouldGenerateCombinationsForThreeParametersWithUnequalValueLengths6(){
		List<List<String>> inputs = new ArrayList<List<String>>();

		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("A1");
		paramAValues.add("A2");
		
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("B1");
		paramBValues.add("B2");
		
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("C1");
		paramCValues.add("C2");
		paramCValues.add("C3");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		
		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("A1 & B1 & C1");
		expectedCombinations.add("A1 & B2 & C2");
		expectedCombinations.add("A2 & B1 & C3");
		expectedCombinations.add("A2 & B2 & C1");
		expectedCombinations.add("A2 & B1 & C2");
		expectedCombinations.add("A1 & B2 & C3");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	
	
	@Test
	public void shouldGenerateCombinationsOfBFormulas(){
		List<List<String>> inputs = new ArrayList<List<String>>();
		
		List<String> paramAValues = new ArrayList<String>();
		paramAValues.add("magazines <: papers");
		paramAValues.add("not(magazines <: papers)");
		
		List<String> paramBValues = new ArrayList<String>();
		paramBValues.add("hh : -4..0");
		paramBValues.add("hh : 164..168");
		paramBValues.add("hh : 1..163");
		
		List<String> paramCValues = new ArrayList<String>();
		paramCValues.add("card(papers) <= 60");
		paramCValues.add("not(card(papers) <= 60");
		
		List<String> paramDValues = new ArrayList<String>();
		paramDValues.add("papers <: -4..0");
		paramDValues.add("papers <: 164..168");
		paramDValues.add("papers <: 1..163");
		
		List<String> paramEValues = new ArrayList<String>();
		paramEValues.add("card(papers) < 60");
		paramEValues.add("not(card(papers) < 60)");
		
		inputs.add(paramAValues);
		inputs.add(paramBValues);
		inputs.add(paramCValues);
		inputs.add(paramDValues);
		inputs.add(paramEValues);
		
		Set<String> expectedCombinations = new HashSet<String>();
		expectedCombinations.add("not(magazines <: papers) & hh : 164..168 & card(papers) <= 60 & papers <: -4..0 & card(papers) < 60");
		expectedCombinations.add("not(magazines <: papers) & hh : 1..163 & not(card(papers) <= 60 & papers <: 1..163 & not(card(papers) < 60)");
		expectedCombinations.add("magazines <: papers & hh : -4..0 & card(papers) <= 60 & papers <: 1..163 & not(card(papers) < 60)");
		expectedCombinations.add("magazines <: papers & hh : 164..168 & not(card(papers) <= 60 & papers <: -4..0 & not(card(papers) < 60)");
		expectedCombinations.add("not(magazines <: papers) & hh : -4..0 & not(card(papers) <= 60 & papers <: 164..168 & card(papers) < 60");
		expectedCombinations.add("magazines <: papers & hh : 164..168 & card(papers) <= 60 & papers <: 1..163 & card(papers) < 60");
		expectedCombinations.add("magazines <: papers & hh : 1..163 & card(papers) <= 60 & papers <: 164..168 & card(papers) < 60");
		expectedCombinations.add("magazines <: papers & hh : 164..168 & card(papers) <= 60 & papers <: 164..168 & not(card(papers) < 60)");
		expectedCombinations.add("magazines <: papers & hh : -4..0 & card(papers) <= 60 & papers <: -4..0 & card(papers) < 60");
		expectedCombinations.add("magazines <: papers & hh : 1..163 & card(papers) <= 60 & papers <: -4..0 & not(card(papers) < 60)");
		
		Pairwise pairwise = new Pairwise(inputs);
		Set<String> actualCombinations = pairwise.getCombinationsStrings();
		
		assertEquals(expectedCombinations, actualCombinations);
	}
	
	
	
}
